#pragma once
#include <jsoncpp/json/json.h>
#include <string>
#include "Socket.hpp"
#include<functional>

namespace kzz
{
    
    class Request
    {
    public:
        Request()
        {
        }

        Request(int x, int y, char oper)
            : _x(x), _y(y), _oper(oper)
        {
        }

        std::string Serialize()
        {
            Json::Value root;
            root["x"] = _x;
            root["y"] = _y;
            root["oper"] = _oper;
            Json::FastWriter writer;
            std::string json_str = writer.write(root);
            return json_str;
        }

        bool DeSerialize(std::string &json_str)
        {
            Json::Value root;
            Json::Reader reader;
            bool ok = reader.parse(json_str, root);

            if (ok)
            {
                _x = root["x"].asInt();
                _y = root["y"].asInt();
                _oper = root["oper"].asInt();
            }
            return ok;
        }

        int X()
        {
            return _x;
        }
        int Y()
        {
            return _y;
        }
        char Oper()
        {
            return _oper;
        }

    private:
        int _x;
        int _y;
        char _oper;
    };
    class ReSponse
    {
    public:
        ReSponse() {}
        ReSponse(int result, int code=0)
            : _result(result), _code(code)
        {
        }

        std::string Serialize()
        {
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            std::string json_str = writer.write(root);
            return json_str;
        }

        bool DeSerialize(std::string &json_str)
        {
            Json::Value root;
            Json::Reader reader;
            int ok = reader.parse(json_str, root);
            if (ok)
            {
                _result = root["redult"].asInt();
                _code = root["code"].asInt();
            }
            return ok;
        }
        void SetResult(int ret)
        {
            _result=ret;
        }
        void SetCode(int code)
        {
            _code=code;
        }

        int Result()
        {
            return _result;
        }
        int Code()
        {
            return _code;
        }

    private:
        int _result;
        int _code; // 区分结果是否正确，那种错误
    };

    //"20\r  "
    //"20\r\n "
    //"20\r\n x=9 "
    //"20\r\n x=9 y=9 oper=+   "
     //"20\r\n x=9 y=9 oper=+\r\n   "  完整的一个请求报文
    //"20\r\n x=9 y=9 oper=+ \r\n  20\r\n x=9 y=9 oper=+   "
    const std::string sep = "\r\n";
    using pro_task = std::function<  kzz::ReSponse(kzz::Request& req)    >;
    class Protocol
    {
    public:
        Protocol(pro_task func)
        :_func(func)
         {}

        //对json串添加报头报尾
      void EnCode(std::string& json_str)
        {
            int json_len=json_str.size();
            std::string package=std::to_string(json_len)+sep+json_str+sep;
            json_str=package;
           
        }



        // 判断收到的信息是否完整
        bool DeCode(std::string &buffer_queue, std::string &json_package)
        {
            int pos = buffer_queue.find(sep);
            // 连分隔符都没有，回去继续读
            if (pos == std::string::npos)
                return false;
        //到这里一定是有分隔符的,json_len只是json的长度，不包括报头报尾
     
            int json_len=std::stoi(buffer_queue.substr(0,pos));
     
            int len = json_len  +  pos  +  sep.size()*2;

            if(buffer_queue.size()<len)
            return false;

            //走到这里,buffer里一定有完整的报文，
            //要取的只有中间的json串
            json_package=buffer_queue.substr(pos+sep.size(),json_len);
            //删除buffer中的已经被取到json_package的数据
            buffer_queue.erase(0,len);
           
            return true;
            
        }

        // 通过accept得来的套接字，获取请求，
        // 并对请求做任务处理。然后再通过套接字传回去，这个过程不需要客户端地址的参与
        void GetRequest(std::shared_ptr<kzz::Socket> socket, InetAddr &client)
        {
            std::string buffer_queue;
            while (true)
            {
                // 客户端同样遵守协议规定，传过来的同样是序列化加上code后的信息
                int n = socket->Recv(buffer_queue);
                if (n > 0)
                {

                    // 1.读取成功，开始判断收到的信息是否完整
                    std::string json_package; //用来收取完整的报文
                   bool ok= DeCode(buffer_queue,json_package);
                   if(!ok)//继续读
                   continue;

                   //2.走到这里,json_package里一定是完整的报文
                   //   "x=9 y=9 oper=+"
                   //得到一个反序列化后的请求结果
                   Request req;
                   req.DeSerialize(json_package);
                   //3.对请求做任务处理，要传入针对request的任务处理函数
                   ReSponse res=_func(req);
               
                   //4.序列化,返回一个序列化后的json串
                   std::string json_str=res.Serialize();

                   //5.对这个json串加报头报尾
                   EnCode(json_str);

                   //6.通过套接字发送回去
                   socket->Send(json_str);
                }
                else if (n == 0)
                {
                    // 客户端退出
                    LOG(LogLevel::DBUGER) << "客户端" << client.InetName().c_str() << "退出";
                    break;
                }
                if (n < 0)
                {
                    LOG(LogLevel::DBUGER) << "Recv error";
                    exit(RECV_ERR);
                }
            }
        }

    private:
    pro_task _func;
    };
}